# -*- coding: utf-8 -*-
# @Time     : 2024/3/12 14:25
# @Author   : Long-Long Qiu
# @FileName : pack_worker.py
# @Product  : PyCharm
# @description  : 进行pack计算的worker进程
# import packages
import shutil
import time
import os
import json
from py3dbp import Packer, Bin, Item, Painter
import pickle
import math
import argparse
from multiprocessing import Pool
from tqdm import tqdm
import multiprocessing
import json
from pack_workers import packing_items_sbc
from make_simulate_data import generate_box_data


def run_validation(solution, validate_func):
    bp = BoxPacking()
    validate_method = getattr(bp, validate_func)
    result = validate_method(solution)
    if result:
        bp.save_results(solution, f"{solution}.json")


def packing(box, items, radius_threshold1, radius_threshold2, pre_packing_cubes=True):

    # 预处理：过滤数量小于1的项
    items = list(filter(lambda x: x[4] > 0, items))
    # 1. 获取box的高度
    if type(box[0]) == list or type(box[0]) == tuple:
        # box_length = box[0][0]
        # box_width = box[0][1]
        # box_height = box[0][2]
        box_length = max([be[0] for be in box])
        box_width = max([be[1] for be in box])
        box_height = max([be[2] for be in box])
    elif type(box[0]) == Bin:
        # box_length = float(box[0].width)
        # box_width = float(box[0].height)
        # box_height = float(box[0].depth)
        box_length = float(max([be.width for be in box]))
        box_width = float(max([be.height for be in box]))
        box_height = float(max([be.depth for be in box]))
    else:
        box_length, box_width, box_height = 0, 0, 0

    cubes = list(filter(lambda x: x[5] != 0, items))    # 所有的非盘具
    items = list(filter(lambda x: x[5] == 0, items))    # 所有的盘具

    if sum([ie[4] for ie in items]) > 0:
        heaps = pack_cylinders_2(items)
        heaps = {f"heap-{index + 1}": heap for index, heap in enumerate(heaps)}
    else:
        heaps = {}

    # 2. 将货物进行打包预处理
    # 2.1 预打包盘货：将盘货items转成heaps
    # if sum([ie[4] for ie in items]) > 0:
    #     heaps = pack_cylinders(items, radius_threshold1, radius_threshold2, box_height)
    #     heaps = {f"heap-{index + 1}": heap for index, heap in enumerate(heaps)}
    # else:
    #     heaps = {}

    if pre_packing_cubes:   # 对cubes进行预打包处理
    # 2.2 预打包cubes：将cubes转成heaps
        pre_pack_cubes = pack_cubes2
        cube_heaps, other_cubes, finished = pre_pack_cubes(cubes, box_length, box_width, box_height)

        while not finished:  # 预打包未结束
            # 继续进行预打包
            new_cube_heaps, other_cubes, finished = pre_pack_cubes(other_cubes, box_length, box_width, box_height, start_index=len(cube_heaps))
            cube_heaps = {**cube_heaps, **new_cube_heaps}
        # 3. 装箱
        result = pack_heap(heaps, box, cubes=other_cubes, cube_heaps=cube_heaps)
        return {**heaps, **cube_heaps}, result
    else:
        result = pack_heap(heaps, box, cubes=cubes)
        return heaps, result


def pack_cylinders_2(all_items):
    results = []
    for items in all_items:
        for i in range(items[4]):
            results.append([[[items[0], items[1], items[2], items[3], 0, 0, 0, 'orange']]])
    return results


def pack_cubes2(cubes, box_width, box_height, box_depth, start_index=0):
    # 1. 将木箱、托盘、纸箱分开
    woodens = [cube for cube in cubes if cube[5] == 1]
    trays = [cube for cube in cubes if cube[5] == 2]
    cartoons = [cube for cube in cubes if cube[5] == 3]

    # box_width /= 5
    # box_height /= 5

    results = {}
    flag = True

    # 2. 对不同种类的货物分别做处理
    # 2.1 预打包木箱
    for wooden in woodens:
        pass

    # 2.2 预打包托盘
    other_trays = []
    # 优先在y轴方向上平铺，其次在z轴方向上堆叠，最后在x轴方向上平铺
    for index, tray in enumerate(trays):
        # 获取货物的尺寸和重量
        width, height, depth, weight = tray[0:4]
        # 确定沿着y轴和z轴能放几个货物
        y_layers_num = math.floor(box_height // height)
        z_layers_num = 1
        if width * height / 1000 / 1000 > 0.6 and 100 < weight < 600:
            z_layers_num = math.floor(box_depth // depth)
        # x_layers_num = math.floor(box_width // width) // 20
        x_layers_num = 1
        layers = [[] for _ in range(z_layers_num)]
        x, y, z = 0., 0., 0.
        num = tray[4]
        w, h, d = 0, 0, 0
        for i in range(num):
            layers[d].append([round(width, 2), round(height, 2), round(depth, 2),
                              round(weight, 2), round(x, 2), round(y, 2), round(z, 2)])

            if h == y_layers_num - 1:  # y轴铺满，往z轴堆叠或x轴平铺
                if d == z_layers_num - 1:  # y轴铺满且z轴也堆满了，则往x轴方向平铺
                    w += 1
                    h = 0
                    d = 0
                    if w >= x_layers_num and num > i:  # 车厢放不下
                        other_trays.append([width, height, depth, weight, num - i - 1, 2])
                        break
                else:  # y轴铺满而z轴未堆满，则往z轴方向堆叠
                    h = 0
                    d += 1

                x, y, z = w * width, h * height, d * depth

            else:  # y轴未铺满，沿着y轴方向继续平铺
                h += 1
                y = h * height
        results[f"tray-{index + start_index}"] = list(filter(lambda m: m != [], layers))

    # 2.3 预打包纸箱
    other_cartoons = []
    # 优先在y轴方向上平铺，其次在z轴方向上堆叠，最后在x轴方向上平铺
    for index, cartoon in enumerate(cartoons):
        # 获取货物的尺寸和重量
        width, height, depth, weight = cartoon[0:4]
        # 确定沿着y轴和z轴能放几个货物
        y_layers_num = math.floor(box_height // height)
        z_layers_num = math.floor(box_depth // depth)
        # x_layers_num = math.floor(box_width // width) // 20
        x_layers_num = 1
        layers = [[] for _ in range(z_layers_num)]
        x, y, z = 0., 0., 0.
        num = cartoon[4]
        w, h, d = 0, 0, 0
        for i in range(num):
            layers[d].append([round(width, 2), round(height, 2), round(depth, 2),
                              round(weight, 2), round(x, 2), round(y, 2), round(z, 2)])

            if h == y_layers_num - 1:   # y轴铺满，往z轴堆叠或x轴平铺
                if d == z_layers_num - 1:   # y轴铺满且z轴也堆满了，则往x轴方向平铺
                    w += 1
                    h = 0
                    d = 0
                    if w >= x_layers_num and num > i:   # 车厢放不下
                        other_cartoons.append([width, height, depth, weight, num - i - 1, 3])
                        break
                else:   # y轴铺满而z轴未堆满，则往z轴方向堆叠
                    h = 0
                    d += 1

                x, y, z = w * width, h * height, d * depth

            else:   # y轴未铺满，沿着y轴方向继续平铺
                h += 1
                y = h * height
        results[f"cartoon-{index + start_index}"] = list(filter(lambda m: m != [], layers))

    # if len(other_trays) > preMinNum or len(other_cartoons) > preMinNum:
    if other_trays or other_cartoons:
        flag = False
    return results, other_trays + woodens + other_cartoons, flag


def pack_heap(heaps, boxes, cubes=[], cube_heaps={}, use_box_height=True):
    """
    将heap装载到box中
    :param heaps:
    :param boxes:
    :param cubes:
    :param use_box_height: 是否使用bin的高度作为heap的高度(可以用于防止在heap上方继续堆叠)
    :return:
    """

    # 1. 初始化packer对象，并将box添加到packer中
    packer = Packer()
    for idx, b in enumerate(boxes):
        if type(b) == list or type(b) == tuple:
            bin = Bin(f"car-{idx}", (b[0], b[1], b[2]), b[3], corner=0, put_type=0, price=b[4])
            packer.addBin(bin)
        elif type(b) == Bin:
            packer.addBin(b)

    # 2. 添加cylinder的heap对象
    colors = ['orange', 'olive', 'green', 'red', 'blue', 'purple', 'yellow']
    for name, heap in heaps.items():
        index = int(name.split('-')[1])
        width = heap[0][-1][4] + heap[0][-1][0]
        height = heap[0][0][1]
        depth = [item for layer in heap for item in layer][-1][6] + heap[0][0][2]
        if use_box_height:
            # depth = float(packer.bins[0].depth)
            depth = max([float(ib.depth) for ib in packer.bins])
        weight = sum([item[3] for layer in heap for item in layer])

        # print('cylinder-heap', width, height, depth)
        packer.addItem(
            Item(partno=f'Box-{index + 1}', name=name, typeof='heap',
                 WHD=(width, height, depth), weight=weight, level=0, loadbear=100,
                 updown=False, color=colors[index % len(colors)]))

    # 3. 添加cube的heap对象
    for name, heap in cube_heaps.items():
        if not heap:
            continue
        level_map = {'wooden': 1, 'tray': 2, 'cartoon': 3}
        # width = heap[0][-1][0] + heap[0][-1][4]
        width = max([ie[0] + ie[4] for layer in heap for ie in layer])
        # height = heap[0][-1][1] + heap[0][-1][5]
        height = max([ie[1] + ie[5] for layer in heap for ie in layer])
        depth = heap[-1][0][2] + heap[-1][0][6]
        # weight = heap[0][0][3]
        weight = sum([ie[3] for layer in heap for ie in layer])
        kind, index = name.split('-')[0], int(name.split('-')[1])
        packer.addItem(Item(partno=f"CubeBox-{index + 1}", name=name, typeof='cube',
                            WHD=(width, height, depth), weight=weight, level=level_map[kind],
                            loadbear=100, updown=False, color=colors[index % len(colors)]))

    # 4. 添加额外的cubes(1为木箱，2为托盘，3为纸箱，使用item.level进行区分)
    cube_colors = {
        1: 'purple',    # 木箱为紫色
        2: 'cyan',  # 托盘蓝绿色
        3: 'gray'   # 纸箱为灰色
    }
    cube_num = 1
    for index, cube in enumerate(cubes):
        n = cube[4]
        for _ in range(n):
            packer.addItem(Item(partno=f'Box-{cube_num + len(heaps)}', name=f'cube{cube_num + len(heaps)}', typeof='cube', WHD=(cube[0], cube[1], cube[2]),
                 weight=cube[3], level=cube[5], loadbear=cube[3],
                 updown=False, color=cube_colors[cube[5]]))
            cube_num += 1

    # 5. 装箱
    packer.pack(
        bigger_first=False,
        distribute_items=False,
        fix_point=True,
        check_stable=True,
        support_surface_ratio=1.,
        number_of_decimals=2
    )
    # put order
    packer.putOrder()
    return packer


def packing_items(items, all_cars, result_path, log_path, config_parameters={}, user_ip='127.0.0.1',
                  pre_packing_cubes=True, pre_min_num=20, top_num=10):
    start = time.time()
    # 1. 准备结果文件
    if not os.path.isdir(result_path):
        os.makedirs(result_path)
    absolute_file_path = f'{result_path}/result.json'
    if not os.path.exists(absolute_file_path):
        with open(absolute_file_path, 'w') as fp:
            json.dump({
                'finished': False,
                'result': []
            }, fp)

    # 2. 获取货物、车辆等信息
    if sum([ie[4] for ie in items]) < pre_min_num:
        pre_packing_cubes = False
    # radius1 = int(config_parameters['dish']['second_dish_radius_1']) / 100
    # radius2 = int(config_parameters['dish']['second_dish_radius_2']) / 100
    radius1 = 500
    radius2 = 700
    cars = [(car['size'][0], car['size'][1], car['size'][2], car['loadbear'], car['price']) for car in all_cars]
    cars = sorted(cars, key=lambda x: x[4], reverse=True)

    ie_v, ie_w = 0, 0
    for ie in items:
        ie_w += ie[3] * ie[4]
        ie_v += ie[0] * ie[1] * ie[2] * ie[4]

    results = []
    # 3. 计算单车方案
    suc_num = 0
    for index, b in enumerate(cars):
        box = Bin(f"car-{index}", (b[0], b[1], b[2]), b[3], 0, put_type=0, price=b[4])
        box_v = float(box.getVolume())
        box_w = float(box.max_weight)
        if box_v < ie_v or box_w < ie_w:
            continue
        # 3.1 尝试装箱
        heaps, pack_result = packing([box], items, radius1, radius2, pre_packing_cubes=pre_packing_cubes)
        # 3.2 判断装箱是否成功
        if len(pack_result.bins[0].items) == pack_result.total_items:
            suc_num += 1
            # 3.3 计算空间利用率、载重利用率等信息
            space_ratio = ie_v / box_v
            weight_ratio = ie_w / box_w
            car_type = f"car{index}-{[a / 1000 for a in cars[index][0:3]]}"
            # 3.4 结果汇总
            results.append({
                'status': True,
                'bin_type': [car_type],
                'bin_num': [1],
                'space_ratio': space_ratio,
                'box_weight': box_w,
                'goods_weight': ie_w,
                'weight_ratio': weight_ratio,
                'price': b[4],
                'goods_volume': ie_v / 100 / 100 / 100,
                'bin_volume': box_v / 100 / 100 / 100,
                'heaps': str(pickle.dumps(heaps), encoding='latin1'),
                'packer': str(pickle.dumps(pack_result), encoding='latin1'),
                'car-num': 1
            })
            # 3.5 结果保存
            with open(absolute_file_path, 'w') as fp:
                json.dump({
                    'ts': int(time.time()),
                    'finished': False,
                    'result': results
                }, fp, ensure_ascii=False)

    # 4. 计算多车方案
    car_types = []      # 记录方案是否已经计算
    multi_cars = [[[car]] for car in cars]
    finished = False
    while not finished:
        if len(multi_cars[0][0]) + 1 >= 11:
            break
        # 4.1 生成方案
        print('*' * 30)
        print(f"开始生成{len(multi_cars[0][0]) + 1}车方案")
        print('*' * 30)
        for cars_index in range(len(multi_cars)):
            current_cars = multi_cars[cars_index]
            cars_temp = []
            for current_car in current_cars:
                for car_index, car in enumerate(cars):
                    if car_index > cars_index:
                        continue
                    cars_temp.append(current_car + [car])
            multi_cars[cars_index] = cars_temp

        # 4.2 方案排序
        multi_boxes = [car for c_cars in multi_cars for car in c_cars]

        multi_boxes = sorted(multi_boxes, key=lambda x: sum([c[4] for c in x]), reverse=True)
        # 4.3 计算方案
        print('*' * 30)
        print(f"开始计算{len(multi_cars[0][0])}车方案")
        print('*' * 30)
        current_suc, current_total = 0, 0
        for boxes_index, boxes in enumerate(multi_boxes):
            bin_v = sum([be[0] * be[1] * be[2] for be in boxes])
            bin_w = sum([be[3] for be in boxes])
            if bin_v < ie_v or bin_w < ie_w:
                continue
            current_total += 1
            # 4.4 尝试装箱
            heaps, pack_result = packing(boxes, items, radius1, radius2, pre_packing_cubes=pre_packing_cubes)
            bin_type, bin_num = [], []
            car_type = []
            for bi in pack_result.bins:
                bin_type.append(
                    f"car-{str([float(bi.width) / 1000, float(bi.height) / 1000, float(bi.depth) / 1000])}")
                car_type.append(str(bi.width))
                bin_num.append(1)
            car_type = sorted(car_type, key=lambda x: x)
            car_type = ','.join(car_type)
            if car_type not in car_types:
                # 4.5 判断装箱是否成功
                status = sum([len(ie.items) for ie in pack_result.bins]) == pack_result.total_items
                if status:
                    current_suc += 1
                    # 4.6 计算空间利用率、载重利用率等信息
                    space_ratio = ie_v / bin_v
                    weight_ratio = ie_w / bin_w
                    suc_num += 1
                    print('成功！！！', car_type)
                    # 4.7 追加结果
                    car_types.append(car_type)
                    results.append({
                        'status': True,
                        'bin_type': bin_type,
                        'bin_num': bin_num,
                        'space_ratio': space_ratio,
                        'box_weight': bin_w,
                        'goods_weight': ie_w,
                        'weight_ratio': weight_ratio,
                        'price': sum([bi.price for bi in pack_result.bins]),
                        'goods_volume': ie_v / 100 / 100 / 100,
                        'bin_volume': bin_v / 100 / 100 / 100,
                        'color': {},
                        'heaps': str(pickle.dumps(heaps), encoding='latin1'),
                        'packer': str(pickle.dumps(pack_result), encoding='latin1'),
                        'car-num': len(bin_type)
                    })
                    # 4.8 结果保存
                    with open(absolute_file_path, 'w') as fp:
                        json.dump({
                            'ts': int(time.time()),
                            'finished': False,
                            'result': results
                        }, fp, ensure_ascii=False)
                    if suc_num >= top_num:
                        finished = True
                else:
                    if 0.1 and current_total > 20:
                        break
            else:
                pass
                # print('重复')

    if finished:
        print('装箱进程结束！！！')
    # 5. 更改结果状态
    with open(absolute_file_path, 'r') as fp:
        data = json.load(fp)
        data['finished'] = True
    with open(absolute_file_path, 'w') as fp:
        json.dump(data, fp, ensure_ascii=False)

    # 6. 日志
    end = time.time()
    print(f"装箱耗时{round(end - start, 3)}秒")
    log_content = {
        'url': '/pack',
        'user_ip': user_ip,
        'start_time': int(start),
        'time': round(end - start, 3),
        'goods': items,
        'cars': all_cars,
        'config': config_parameters,
        'result': results
    }
    with open(log_path, 'a') as fp:
        fp.write(json.dumps(log_content, ensure_ascii=False) + '\n')


class BoxPacking(object):
    def __init__(self, items, all_cars, result_path, log_path, config_parameters={},
                 user_ip='127.0.0.1', pre_packing_cubes=True, pre_min_num=20, top_num=10):
        # 使用一行代码将所有参数赋值给self
        self.items = items
        self.all_cars = all_cars
        self.result_path = result_path
        self.log_path = log_path
        self.config_parameters = config_parameters
        self.user_ip = user_ip
        self.pre_packing_cubes = pre_packing_cubes
        self.pre_min_num = pre_min_num
        self.top_num = top_num
        self.start = time.time()
        # 验证存储地址
        if not os.path.isdir(self.result_path):
            os.makedirs(self.result_path)

    def validate_single_vehicle_solution(self, solution):
        index, solution_i = solution
        # 验证单车方案的逻辑
        box = Bin(f"car-{index}", (solution_i[0], solution_i[1], solution_i[2]), solution_i[3],
                  0, put_type=0, price=solution_i[4])
        box_v = float(box.getVolume())
        box_w = float(box.max_weight)
        if box_v < self.ie_v or box_w < self.ie_w:
            return
        # 3.1 尝试装箱
        heaps, pack_result = packing([box], self.items, self.radius1, self.radius2,
                                     pre_packing_cubes=self.pre_packing_cubes)
        # 3.2 判断装箱是否成功
        if len(pack_result.bins[0].items) == pack_result.total_items:
            # 3.3 计算空间利用率、载重利用率等信息
            space_ratio = self.ie_v / box_v
            weight_ratio = self.ie_w / box_w
            car_type = f"car{index}-{[a / 1000 for a in self.cars[index][0:3]]}"
            # 3.4 结果保存
            with open(os.path.join(self.solution_file_path, f"1_{index}.json"), 'w') as fp:
                json.dump({
                'status': True,
                'bin_type': [car_type],
                'bin_num': [1],
                'space_ratio': space_ratio,
                'box_weight': box_w,
                'goods_weight': self.ie_w,
                'weight_ratio': weight_ratio,
                'price': solution_i[4],
                'goods_volume': self.ie_v / 100 / 100 / 100,
                'bin_volume': box_v / 100 / 100 / 100,
                'heaps': str(pickle.dumps(heaps), encoding='latin1'),
                'packer': str(pickle.dumps(pack_result), encoding='latin1'),
                'car-num': 1
                }
                , fp, ensure_ascii=False)

    def validate_multi_vehicle_solution(self, multi_boxes):
        """
        验证多车方案
        :param multi_boxes:
        :return:
        """
        if self.end_solution_gen():
            return
        # 验证多车方案的逻辑
        # 4.3 计算方案
        index, boxes = multi_boxes
        bin_v = sum([be[0] * be[1] * be[2] for be in boxes])
        bin_w = sum([be[3] for be in boxes])
        if bin_v < self.ie_v or bin_w < self.ie_w:
            return
        self.current_total += 1
        # 4.4 尝试装箱
        heaps, pack_result = packing(boxes, self.items, self.radius1, self.radius2, pre_packing_cubes=self.pre_packing_cubes)
        bin_type, bin_num = [], []
        car_type = []
        for bi in pack_result.bins:
            bin_type.append(
                f"car-{str([float(bi.width) / 1000, float(bi.height) / 1000, float(bi.depth) / 1000])}")
            car_type.append(str(bi.width))
            bin_num.append(1)
        car_type = sorted(car_type, key=lambda x: x)
        car_type = ','.join(car_type)
        if car_type in self.car_types:
            return
        # 4.5 判断装箱是否成功
        status = sum([len(ie.items) for ie in pack_result.bins]) == pack_result.total_items
        if status:
            # 4.6 计算空间利用率、载重利用率等信息
            space_ratio = self.ie_v / bin_v
            weight_ratio = self.ie_w / bin_w
            # 4.7 追加结果
            self.car_types.append(car_type)
            # 4.8 保存结果
            with open(os.path.join(self.solution_file_path, f"{len(boxes)}_{index}.json"), 'w') as fp:
                json.dump({
                        'status': True,
                        'bin_type': bin_type,
                        'bin_num': bin_num,
                        'space_ratio': space_ratio,
                        'box_weight': bin_w,
                        'goods_weight': self.ie_w,
                        'weight_ratio': weight_ratio,
                        'price': sum([bi.price for bi in pack_result.bins]),
                        'goods_volume': self.ie_v / 100 / 100 / 100,
                        'bin_volume': bin_v / 100 / 100 / 100,
                        'color': {},
                        'heaps': str(pickle.dumps(heaps), encoding='latin1'),
                        'packer': str(pickle.dumps(pack_result), encoding='latin1'),
                        'car-num': len(bin_type)
                    }
                , fp, ensure_ascii=False)

    def validate_multi_vehicle_solution_mint(self):
        """
        生成处理方案
        :return:
        """
        multi_cars = [[[car]] for car in self.cars]
        multi_boxes_list = []
        print(f"开始生成多车方案")
        while True:
            if len(multi_cars[0][0]) + 1 >= 6:
                break
            # 4.1 生成方案
            for cars_index in range(len(multi_cars)):
                current_cars = multi_cars[cars_index]
                cars_temp = []
                for current_car in current_cars:
                    for car_index, car in enumerate(self.cars):
                        if car_index > cars_index:
                            continue
                        cars_temp.append(current_car + [car])
                multi_cars[cars_index] = cars_temp

            # 4.2 方案排序
            multi_boxes = [car for c_cars in multi_cars for car in c_cars]
            multi_boxes = sorted(multi_boxes, key=lambda x: sum([c[4] for c in x]), reverse=True)
            multi_boxes_list.append(multi_boxes)
        return multi_boxes_list

    def save_results(self, cache_pth, save_pth):
        """
        所有零散的结果读取并保存到最终的结果
        :param result:
        :param filename:
        :return:
        """
        # 读取所有结果
        for cache_i in os.listdir(cache_pth):
            with open(os.path.join(cache_pth, cache_i), "r", encoding="utf-8") as f:
                data = json.load(f)
                self.results.append(data)
        # 保存当前结果
        with open(save_pth, 'w') as fp:
            json.dump({
                'ts': int(time.time()),
                'finished': False,
                'result': self.results
            }, fp, ensure_ascii=False)

    def end_solution_gen(self):
        """
        给定断开条件
        :return:
        """
        solution_list = os.listdir(self.solution_file_path)
        if len(solution_list) >= self.top_num:
            # 如果生成的策略数量已达到要求
            return True
        else:
            return False

    def process_wave(self, progress, nums):
        """
        多进程调用函数，并显示进度条
        :param progress: 函数
        :param nums: 处理序列
        :return:
        """
        # 初始化进程池，这里设置进程数目为4
        data_to_process = list(nums)  # 创建一个要处理的数据列表
        # 初始化Pool对象
        with Pool(processes=10) as pool:  # 使用CPU核心数
            results = pool.map(progress, data_to_process)
        print("完成")
        # with Pool(10) as p:
        #     # 使用 tqdm 创建进度条，total=任务总数
        #     with tqdm(total=len(nums)) as progress_bar:
        #         # imap_unordered 用于多进程迭代，它的返回迭代器结果顺序可能与输入不同
        #         # 但它比 imap 更快，特别是当处理函数有显著不同的执行时间时
        #         for _ in p.imap_unordered(progress, nums):
        #             # 每完成一个任务，进度条更新一次
        #             progress_bar.update(1)

    def main(self):
        start = time.time()
        # 1. 创建中间存储的json文件夹
        self.solution_file_path = f'{self.result_path}/cache'
        if os.path.isdir(self.solution_file_path):
            shutil.rmtree(self.solution_file_path)
        os.makedirs(self.solution_file_path)
        # 2. 获取货物、车辆等信息
        if sum([ie[4] for ie in self.items]) < self.pre_min_num:
            self.pre_packing_cubes = False
        self.radius1 = 500
        self.radius2 = 700
        cars = [(car['size'][0], car['size'][1], car['size'][2], car['loadbear'], car['price']) for car in self.all_cars]
        self.cars = sorted(cars, key=lambda x: x[4], reverse=True)
        ie_v, ie_w = 0, 0
        for ie in self.items:
            ie_w += ie[3] * ie[4]
            ie_v += ie[0] * ie[1] * ie[2] * ie[4]
        self.ie_v = ie_v
        self.ie_w = ie_w
        self.results = []
        # 3. 使用多进程验证单车方案
        solution_list = [[index, soultion] for index, soultion in enumerate(self.cars)]
        self.process_wave(self.validate_single_vehicle_solution, solution_list)
        # 4. 计算多车方案
        self.car_types = [] # 定义多车方案合集，防止重复
        mut_solution_lists = self.validate_multi_vehicle_solution_mint()
        for mut_solution_list in mut_solution_lists:
            # 逐个案例分析
            if self.end_solution_gen():
                break
            # 定义最大运行次数
            self.current_total = 0
            print('*' * 30)
            print(f"开始验证{len(mut_solution_list[0])}车方案")
            print('*' * 30)
            solution_list = [[index, soultion] for index, soultion in enumerate(mut_solution_list)]
            self.process_wave(self.validate_multi_vehicle_solution, solution_list)
        # 5. 更改结果状态,并保存
        self.save_results(self.solution_file_path,  f'{self.result_path}/result_mutil.json')
        print('装箱进程结束！！！')
        # 6. 日志
        end = time.time()
        print(f"装箱耗时{round(end - start, 3)}秒")
        log_content = {
            'url': '/pack',
            'user_ip': self.user_ip,
            'start_time': int(start),
            'time': round(end - start, 3),
            'goods': self.items,
            'cars': self.all_cars,
            'config': self.config_parameters,
            'result': self.results
        }
        with open(self.log_path, 'a') as fp:
            fp.write(json.dumps(log_content, ensure_ascii=False) + '\n')

    def monitor_new_files(self):
        """监视目录中新文件的出现"""
        directory = f'{self.result_path}/cache'
        new_file = f'{self.result_path}/result_mutil.json'
        known_files = set(os.listdir(directory))
        while not os.path.isfile(new_file):
        # while True:
            current_files = set(os.listdir(directory))
            new_files = current_files - known_files
            if new_files:
                print(f"New files in {directory}: {new_files}")
                known_files = current_files
            # time.sleep(0.0001)  # 检查间隔

def pack_work_main(items, cars, resultPath, logPath):
    parser = argparse.ArgumentParser(description='启动pack_worker进程')
    parser.add_argument('--items', type=str, default=items, help='货物')
    parser.add_argument('--cars', type=str, default=cars, help='车辆')
    parser.add_argument('--resultPath', type=str, default=resultPath, help='session结果保存路径')
    parser.add_argument('--logPath', type=str, default=logPath, help='日志保存路径')
    parser.add_argument('--configParameters', type=str, default='{}', help='算法配置项')   # 暂时不用
    parser.add_argument('--userIp', type=str, default='127.0.0.1', help='请求者ip地址')
    args = parser.parse_args()
    items = json.load(open(args.items, 'r'))
    cars = json.load(open(args.cars, 'r'))
    configParameters = json.loads(args.configParameters)
    FileGenerator = BoxPacking(items, cars, args.resultPath, args.logPath, configParameters, user_ip=args.userIp, top_num=20)
    # 创建两个进程：一个运行文件生成器，一个运行文件监视器
    FileGenerator.main()
    return


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='启动pack_worker进程')
    parser.add_argument('--items', type=str, default='./goods/55dca2464acd47550e25c6cfc0377398_goods.json', help='货物')
    parser.add_argument('--cars', type=str, default='./cars/cars1.json', help='车辆')
    parser.add_argument('--resultPath', type=str, default='./results/55dca2464acd47550e25c6cfc0377398_goods', help='session结果保存路径')
    parser.add_argument('--logPath', type=str, default='./pack.log', help='日志保存路径')
    parser.add_argument('--configParameters', type=str, default='{}', help='算法配置项')   # 暂时不用
    parser.add_argument('--userIp', type=str, default='127.0.0.1', help='请求者ip地址')

    result_dict = {}
    for i in range(300):

        items = generate_box_data()
        args = parser.parse_args()
        # items = json.load(open(args.items, 'r'))
        # items = json.loads(args.items)
        cars = json.load(open(args.cars, 'r'))
        configParameters = json.loads(args.configParameters)

        time1 = time.time()
        packing_items(items, cars, args.resultPath, args.logPath, configParameters, user_ip=args.userIp, top_num=20)
        total_time1 = time.time()-time1
        print(f"单进程-----总计耗时{time.time()-time1}")

        time2 = time.time()
        FileGenerator = BoxPacking(items, cars, args.resultPath, args.logPath, configParameters, user_ip=args.userIp, top_num=20)
        # 创建两个进程：一个运行文件生成器，一个运行文件监视器
        generator_process = multiprocessing.Process(target=FileGenerator.main)
        monitor_process = multiprocessing.Process(target=FileGenerator.monitor_new_files)
        # 启动进程
        generator_process.start()
        monitor_process.start()

        # 等待所有进程完成
        generator_process.join()
        monitor_process.join()
        total_time2 = time.time()-time2
        print(f"多进程1-----总计耗时{time.time()-time2}")

        time3 = time.time()
        packing_items_sbc(items, cars, args.resultPath, args.logPath, configParameters, user_ip=args.userIp, top_num=20)
        total_time3 = time.time()-time3
        print(f"多进程2-----总计耗时{time.time()-time3}")

        result_dict[i] = [len(items), total_time1, total_time2, total_time3]
        print(result_dict[i])
    print(result_dict)
    # 将字典保存到JSON文件中
    with open('./data.json', 'w') as json_file:
        json.dump(result_dict, json_file)




        # # 对比一致性
        # new_file = f'{args.resultPath}/result1.json'
        # old_file = f'{args.resultPath}/result.json'
        #
        # new_results = json.load(open(new_file, 'r'))
        # new_results = sorted(new_results['result'], key= lambda x:x['price'])
        # pn = new_results[0]
        # pn["heaps"] = 0
        # pn['packer'] = 0
        # print(pn)
        #
        #
        # old_results = json.load(open(old_file, 'r'))
        # old_results = sorted(old_results['result'], key= lambda x:x['price'])
        # pn = old_results[0]
        # pn["heaps"] = 0
        # pn['packer'] = 0
        # print(pn)



